VMware VM の CPUID を vmx を編集してマスクする
目的と制約
各種ソフトウエアが行う CPUID 命令によるプロセッサの同定で、異なるプロセッサとして判定されないようにしたい
ライセンスなど認証し直すのは手間であり、よりポータビリティを確保したい
x86_64 CPU を対象とする
ただし確認したのは同一メーカー、1世代あとのプロセッサのマシンへの VM の移植のみ
別メーカー、いくつもの世代を経てかなり feature flags が変わってしまっている場合のことはわからない
今回のシチュエーションでは AMD Ryzen 5 PRO 2400GE から AMD Ryzen 5 PRO 3400GE へ VM を移動したかった
表記
bit 列の範囲を表すとき、0 bit は LSB である
Intel の資料 (後述) に合わせる
おおまかな使い方は古い Intel の資料を参考にした
*bit ~ *bit のような表記が LSB を 0bit とする表記であることに注意するとよい
常識なのかもしれないが、わからなかった
あたらしめの Intel CPU の Family ID については 2012年 に作られたであろう Intel のものらしい資料を参考にした
ものらしい、としたのは大学のドメインでホスティングされているため、本当にそうなのか確認できないから
実際の動作確認では、正しく取れていることを確認するために CPUID をわかりやすく表示してくれるツールを利用した
開発を macOS 上で行っていたため、Intel の出している MacCPUID というツールを使って突合した
また、多数のプロセッサがどのような値を CPUID 命令で返すかは、たくさんのダンプデータが落ちているサイトがあったで参考にした
(StackOverflow を眺めていたら見つけた)
プロセッサが同定される差異に一般に使われるであろう値は Intel の資料を参考にした
EAX=0 で CPUID 命令を実行すると得られる Vendor ID
EAX=1 で CPUID 命令を実行すると得られる Processor Signature
EAX=80000002h, EAX=80000003h, EAX=80000004h で CPUID 命令を実行すると得られる Brand String
EAX=1 にして CPUID 命令を実行したときに EBX レジスタの 0 ~ 7 ビットに返る Brand ID という値が最近のプロセッサでは使われていないようである、ということを確認するまで時間がかかった
所持しているマシンについて 0x0 (非対応を示す) しか帰ってこなかったがパースの仕方が悪いのかも? と思って不安になっていた
CPUID dumps を見ることで、ほかのプロセッサでも使われていないんだなと納得することができた
CPUID 命令の返り値をマスクする vmx の構文について vmx の構文は有志が勝手に調べているだけで、本来 Enterprise な製品についている機能を無理矢理有効にするようなものであるため、公式の資料は存在しない
今回の CPUID のマスクであれば、本来は vCenter Server から UI で設定するよう
VMware のフォーラムの投稿を参考にした
Brand String を除く値へのマスク
構文: cpuid.{in-eax}.{out-register} = "{mask}"
右辺の mask は 2進数表記 (binary notation)
mask はある桁について適用しないということができ、しない箇所については - と書くことになる
例: cpuid.1.eax = "----000000001001--00011011101010"
これは EAX レジスタが 1 の状態で CPUID 命令が実行されたときに、EAX レジスタに右辺の mask が適用されるということである
この mask は 31 から 28、15 から14 bit の区間について mask せずに生の値を出力する
注意すべきこととして、命令によって予約領域 (将来のため、何の値が入っているか確定していない領域) がある場合、その予約領域をマスクすると VMware の VMM は値を受けつけないようであること
たとえば cpuid.1.eax は 31 から 28、15 から14 bit の区間は予約されており - で表記しておかないと適用されない
Brand String のマスク
直接文字列を指定する構文が用意されている
cpuid.80000002f.eax, cpuid.2147483650.eax と表記しても、マスクは行えない
構文: cpuid.brandstring = "{brand string}"
例: cpuid.brandstring = "AMD Ryzen 5 PRO 2400GE w/ Radeon Vega Graphics "